package com.xyzwps.paimon.furina.modules.auth.app

import com.xyzwps.paimon.furina.common.*
import com.xyzwps.paimon.furina.infra.*
import com.xyzwps.paimon.furina.middleware.AuthMW
import com.xyzwps.paimon.furina.modules.me.RichMeInfoDTO
import jakarta.servlet.http.Cookie
import org.springdoc.webmvc.core.fn.SpringdocRouteBuilder.route
import org.springframework.stereotype.Component
import org.springframework.web.servlet.function.RouterFunction
import org.springframework.web.servlet.function.ServerRequest
import org.springframework.web.servlet.function.ServerResponse
import kotlin.time.DurationUnit

@Component
class AuthApis(
    private val app: AuthApplication,
    private val authMW: AuthMW
) {

    private val unauth: RequestFilter = authMW::unauth
    private val shouldAuth: RequestFilter = authMW::shouldAuth

    companion object {
        private const val TAG = "Auth"
    }

    fun router(): RouterFunction<ServerResponse> = route()
        .POST("/login/vcode", acceptJson, hf(unauth, handler = ::loginVcode)) {
            it.tag(TAG)
                .operationId("send-login-vcode")
                .summary("Send login vcode")
                .reqBody(RegisterVcodePayload::class.java)
                .respOK(OK::class.java)
        }
        .POST("/login", acceptJson, hf(unauth, handler = ::login)) {
            it.tag(TAG)
                .operationId("login")
                .summary("Login")
                .reqBody(LoginPayload::class.java)
                .respOK(RichMeInfoDTO::class.java)
        }
        .POST("/register/vcode", acceptJson, hf(unauth, handler = ::registerVcode)) {
            it.tag(TAG)
                .operationId("send-register-vcode")
                .summary("Send register vcode")
                .reqBody(RegisterVcodePayload::class.java)
                .respOK(OK::class.java)
        }
        .POST("/register", acceptJson, hf(unauth, handler = ::register)) {
            it.tag(TAG)
                .operationId("register")
                .summary("Register")
                .reqBody(RegisterPayload::class.java)
                .respOK(OK::class.java)
        }
        .POST("/logout", hf(shouldAuth, handler = ::logout)) {
            it.tag(TAG)
                .operationId("logout")
                .summary("Logout")
                .desc(shouldAuth = true)
                .respOK(OK::class.java)
        }
        .build()

    fun registerVcode(req: ServerRequest): JsonResponse {
        val payload = req.validatedBody<RegisterVcodePayload>()
        app.registerVcode(payload.phone)
        return JsonResponse().body(OK)
    }

    fun register(req: ServerRequest): JsonResponse {
        val payload = req.validatedBody<RegisterPayload>()
        app.register(payload)
        return JsonResponse().body(OK)
    }

    fun loginVcode(req: ServerRequest): JsonResponse {
        val payload = req.validatedBody<RegisterVcodePayload>()
        app.loginVcode(payload.phone)
        return JsonResponse().body(OK)
    }

    fun login(req: ServerRequest): JsonResponse {
        val (me, jwt) = app.login(req.validatedBody<LoginPayload>())
        val cookie = Cookie(Cookies.TOKEN_NAME, jwt.token).apply {
            path = "/"
            isHttpOnly = true
            maxAge = jwt.maxAge.toInt(DurationUnit.SECONDS)
        }
        return JsonResponse().cookie(cookie).body(me)
    }

    fun logout(req: ServerRequest): JsonResponse {
        val cookie = Cookie(Cookies.TOKEN_NAME, "").apply {
            path = "/"
            isHttpOnly = true
            maxAge = 0
        }
        return JsonResponse().cookie(cookie).body(OK)
    }
}